Buttons that call out
This is the outbound half of the bridge: a button press, a state change, a Crestron Home scene or a schedule reaching out to anything on the network — over HTTP, or as a raw UDP datagram or TCP command — with no driver written for it.
Where a request fires from​
A request can be attached in two places on a control:
- On entering a state — fired whenever the control enters that state, however it got there: a press, a Crestron Home program, an inbound webhook, or an auto-revert.
- On every press — fired on any press, before the state changes, even for a status-only control.
Open a control in the setup app, expand a state (or the On every press section), and press Add request.
How the request leaves the box — HTTP, UDP or TCP​
Each request has a Send as selector that decides the transport:
| Send as | What it does | When to use it |
|---|---|---|
| HTTP request | An HTTP(S) call — method, URL, headers, body. The original, most-used path. | REST APIs, Shelly/Tasmota/Hue, Home Assistant, anything with a web endpoint. |
| UDP datagram | One datagram, fire-and-forget. Broadcast addresses are allowed. | Gear controlled by a single UDP command — some amps, lighting, wake-on-LAN-style triggers. |
| TCP (connect + send) | Connect, send the payload, optionally read the reply, close. | Projectors, matrix switchers and processors that expose a raw command port. |
HTTP fills in a URL; UDP and TCP fill in a Host and Port instead.
An HTTP request​
| Field | What it is |
|---|---|
| Method | GET, POST, PUT, PATCH or DELETE. |
| URL | The endpoint to call. May contain placeholders. |
| Body | The request body, for POST/PUT/PATCH. Templated. Sent verbatim — no escape processing (a JSON body full of backslashes stays exactly as typed). |
| Content-Type | Defaults to application/json. |
| Headers | Any headers the endpoint needs. Header values are templated. |
| Authentication | None, Basic (user + password), Bearer token, or a header key (e.g. X-API-Key). |
| Ignore TLS certificate errors | For LAN gear with a self-signed certificate. Leave off for anything on the internet. |
A UDP or TCP request​
| Field | What it is |
|---|---|
| Host | The device — a hostname, an IP, or (UDP) a broadcast address. Templated. |
| Port | 1–65535. |
| Payload | The bytes to send. Templated, and — unlike an HTTP body — escape-processed so \r, \n and the like become real bytes. |
| Wait for a reply (TCP) | After sending, read whatever the device answers — until it closes, goes quiet, or the timeout passes — so you can confirm the result. Off = send and close. |
A UDP datagram is sent and forgotten — there is no delivery confirmation, by design. A TCP action opens a fresh connection, sends, optionally reads once, and closes; it does not hold a session open. For gear that needs a persistent connection or bidirectional streaming, this is the wrong tool.
Common to every transport​
| Field | What it is |
|---|---|
| Timeout | How long to wait. Defaults to 10 seconds, capped at 30 — a tile must not hang on a slow endpoint. |
| Delay before sending | Wait this long before firing. See macros. |
Placeholders​
Any URL, header value, HTTP body or UDP/TCP payload can carry placeholders that are filled in when the request fires:
| Placeholder | Value |
|---|---|
{element} / {index} | The control's number. |
{elementName} | The control's name. |
{state} | The state index being entered. |
{stateName} | That state's label. |
{value} | A value an inbound webhook passed in. |
{timestamp} | The current time, ISO-8601 UTC. |
{var:name} | A named variable — settable by a webhook, so an outside value can flow into a request. |
An unknown placeholder is left exactly as written rather than blanked, so a typo like {stat} arrives at
the far end and tells you what went wrong — rather than silently sending nothing.
Payloads: terminators and raw bytes​
Control gear usually needs a command terminator — a carriage return, a line feed — that you cannot type into a text box. On a UDP or TCP payload (not an HTTP body), these escape sequences are turned into the real bytes before sending:
| Escape | Byte |
|---|---|
\r | carriage return |
\n | line feed |
\t | tab |
\0 | null |
\xHH | any byte, as two hex digits (e.g. \x02 for STX) |
\\ | a literal backslash |
So a projector's PWR ON command that must end in a carriage return is typed as PWR ON\r, and an STX/ETX
framed command as \x02PWR ON\x03.
Only UDP/TCP payloads are decoded this way. An HTTP body is sent byte-for-byte as typed, so a JSON body keeps its backslashes intact.
Sequencing a macro​
A state or a press can fire a list of requests, in order. Give each a delay and the list becomes a macro:
POST http://gate/unlock— delay 0GET http://light/on— delay 2000
"Unlock the gate, wait two seconds, turn the light on" — without a scripting language for it. The requests in a list can mix transports: an HTTP call, then a TCP command, then a UDP datagram.
Confirming the result​
By default a press is optimistic: the driver fires the request and moves the control to the new state whether or not the device actually did anything. Confirming the result makes it honest — the driver reads the device's reply and sets the state from what the device actually reports. The one thing worse than a device that doesn't respond is a tile that says it did.
Turn on Read on a request and pick how to pull a value out of the reply:
| Read | What it takes from the reply |
|---|---|
| JSON path | A dotted path such as result.relay.0.ison. Each segment steps in one level, and a numeric segment indexes into an array — relay.0 is the first item of relay. It is a deliberately simplified path, not full JSONPath (no $, no filters): it is configured in a text box by an installer, and the job is almost always "reach two levels in and read a value". The path must land on a single value (a boolean, number or string); a path that stops on an object or an array reads nothing. |
| Regex (first group) | The first capture group of a regular expression — POWER=(\w+) reads ON from STATUS: POWER=ON. With no capture group, the whole match is used. |
| Whole body | The entire reply, trimmed — for a device that answers with a bare 1 and nothing else. |
Then add a value → state row for each value the reply might carry. For a Shelly relay with two states:
| Value | → State |
|---|---|
false | Off (0) |
true | On (1) |
Use add for another row and remove to delete the whole mapping and go back to an optimistic control.
Three things make this forgiving in practice:
- Matching is case- and whitespace-insensitive.
True,trueandONall match the same row — you never have to know which spelling your device happens to send. - A bare number that is already a valid state index maps to itself. A device that just answers
2lands on state 2 with no rows at all; you only need a value → state table when the reply isn't already the index. - A reply it can't read leaves the state alone. If the device answers with something the mapping can't turn into a state — malformed JSON, an HTML error page, an empty reply — the driver treats it as "couldn't tell" and leaves the control unchanged rather than guessing or faulting. A garbled reply is safe.
There has to be a reply to read. HTTP always has a response body, so Read works on its own. A TCP action only has something to read when Wait for a reply is on. UDP is fire-and-forget — it can't confirm anything.
Use Send test request while you build the mapping: it shows the exact reply the device sent, so you can see the value your JSON path or regex lands on before you write the state rows.
Auto-revert: timing a state out​
A state can be set to leave itself automatically after a timeout — the self-cancelling "cooker switch". On a state, enable Leave this state automatically after a timeout, set After (seconds), and pick the state to Go to.
- The revert is a real state entry: it fires the target state's event and its On entering requests, exactly as if a program had set it. It is not a display trick.
- If the control drives the tile, the tile's status line shows a live countdown —
2 mins remaining,45s remaining— until it reverts. - Any other change to the control — a press, a webhook, a programming action — cancels the pending revert. The timer is never left armed behind a manual change.
If the processor reboots while a countdown is running, the control comes back in its restored (or forced) state with no timer armed — it will not revert. This is deliberate parity with the driver it replaces. See Limitations and notes.
Send a test request​
The single most useful button in the app. Send test request fires the request from the driver (not the browser, so it reaches the LAN and applies the same rules a real press would) and shows exactly what came back — the status code or socket result, the time it took, and the response body or reply.
Every misconfigured header, wrong path, wrong port or unreachable host is caught here in a second, instead of becoming a return visit. Fire the request, read the response, fix it, fire it again.
The activity log​
The Activity tab shows the last ~100 calls in and out, newest first — each with its direction, transport, target, status and timing. It is the fastest way to answer "did that actually fire, and what did it say?" without opening a processor console.
The activity log lives in the driver's memory and is cleared on a reboot. It is a commissioning and debugging aid, not a permanent record.